package jdesktop.appbar;

import static jdesktop.appbar.Orientation.HORIZONTAL;

import java.awt.*;

public class GeomUtil
{


    public static Rectangle initRect(Rectangle rect)
    {
        if (rect==null)
            rect = new Rectangle();
        return rect;
    }


    public static void extend(Rectangle rect, Orientation orientation, int extendBy)
    {
        if (orientation==HORIZONTAL)
            rect.width += extendBy;
        else
            rect.height += extendBy;
    }

    public static void offset(Rectangle r, Orientation orientation, int offset)
    {
       if (orientation==HORIZONTAL)
            r.x += offset;
        else
            r.y += offset;
    }

    /**
     * Set the range of an axis on a rectangle. The vertical extent sets 
     *
     * @param rect          The rectangle to set.
     * @param orientation   The orientation of the axis to set.
     * @param extent        The extent of the axis.
     */
    public static void setExtent(Rectangle rect, Orientation orientation, Extent extent)
    {
        if (orientation==HORIZONTAL)
        {
            rect.x = extent.getStart();
            rect.width = extent.getFinish() - extent.getStart();
        }
        else
        {
            rect.y = extent.getStart();
            rect.height = extent.getFinish() - extent.getStart();
        }
    }

    public static void sizeExtent(Extent extent, boolean origin, int size)
    {
        if (origin)
            extent.setFinish(extent.getStart() + size);
        else
            extent.setStart(extent.getFinish() - size);
    }

    static public Extent getExtent(Rectangle r, Orientation orientation)
    {
        if (orientation==HORIZONTAL)
            return new Extent (r.x, r.x + r.width);
        else
            return new Extent (r.y, r.y + r.height);
    }

    /**
     * Sets a pair of insets on an {@link Insets} instance to the values given.
     * @param insets        The insets to set
     * @param orientation   The orientation of the insets to set
     * @param values        The values to set. The first value is the top/left and the second
     *  value is the bottom/right.
     * @return For convenience, {@code insets}.
     * @see #getInsets(java.awt.Insets, Orientation)
     */
    public static Insets setInsets(Insets insets, Orientation orientation, int[] values)
    {
        if (orientation==Orientation.HORIZONTAL)
        {
            insets.left = values[0];
            insets.right = values[1];
        }
        else
        {
            insets.top = values[0];
            insets.bottom = values[1];
        }
        return insets;
    }

    public static void setInset(Insets insets, Orientation orientation, boolean atOrigin, int value)
    {
        if (orientation==Orientation.HORIZONTAL)
        {
            if (atOrigin)
                insets.left = value;
            else
                insets.right = value;
        }
        else
        {
            if (atOrigin)
                insets.top = value;
            else
                insets.bottom = value;
        }
    }

    public static int getInset(Insets insets, Orientation orientation, boolean atOrigin)
    {
        int value;
        if (orientation==Orientation.HORIZONTAL)
        {
            if (atOrigin)
                value = insets.left;
            else
                value = insets.right;
        }
        else
        {
            if (atOrigin)
                value = insets.top;
            else
                value = insets.bottom;
        }
        return value;
    }


    /**
     * Fetches a pair of horizontal or vertical insets.
     * @param insets            The insets to fetch from.
     * @param orientation       The orientation of the pair of insets to fetch.
     * @return The pair of insets for the given orientation. The inset at index 0 is closest
     * to the origin (i.e. left or top); the inset at index 1 is furthest from the origin,
     * (i.e. right or bottom.)
     */
    static public int[] getInsets(Insets insets, Orientation orientation)
    {
        if (orientation==HORIZONTAL)
            return new int[]{insets.left, insets.right};
        else
            return new int[]{insets.top, insets.bottom};
    }



    /**
     * Fetches the pair of inset values for a given orientation, and order.
     * The insets may be re-ordered to place the one furthest from the origin first
     * by setting the {@code originLast} parameter to {@code true}.
     *
     * @param insets        The insets to fetch values from
     * @param orientation   The orientation of the insets fo fetch.
     * @param originLast   If {@code true} the insets are ordered so that the one furthest from
     *  the origin is placed first. If this value is set to the isOrigin of the Edge, it has the
     *  effect of putting at index[0] the "front" edge, i.e. the long edge that is not on
     * the edge of the screen.
     * @return The insets, ordered according to {@code originLast}.
     * @see #getInsets(java.awt.Insets, Orientation)
     */
    static public int[] getInsets(Insets insets, Orientation orientation, boolean originLast)
    {
        int[] values = getInsets(insets, orientation);
        if (!originLast)
        {
            int tmp = values[0];
            values[0] = values[1];
            values[1] = tmp;
        }
        return values;
    }

    /**
     * Retrieves the size of a rectangle along an axis.
     * @param r             The rectangle to retrieve the axis size.
     * @param orientation   The orientation of the axis to retrieve.
     * @return The width or height of the rectangle, as determined by the {@code orientation}.
     */
    public static int getSize(Rectangle r, Orientation orientation)
    {
        return (orientation==HORIZONTAL) ? r.width : r.height;
    }

    public static int getExtentStart(Rectangle r, Orientation orientation)
    {
        return (orientation==HORIZONTAL) ? r.x : r.y;        
    }

    public static int getExtentFinish(Rectangle r, Orientation orientation)
    {
        return (orientation==HORIZONTAL) ? r.x+r.width : r.y+r.height;
    }

    /**
     * Rotates the value on a Sides instance from one edge to another.
     * @param sides     The sides instance to transform.
     * @param from      The edge to rotate from. The intiial settings of the {@code sides} instance
     *  correspond to this edge.
     * @param to        The edge to rotate to. The settings are rotated to correspond to this edge.
     * @param work      A work sides instance.
     * @return
     */
    public static Sides rotate(Sides sides, Edge from, Edge to, Sides work)
    {
        if (from!=to)
        {
            for (int i=0; i<4; i++)
            {
                sides.set(to, work.isSet(from));
                to = to.getAdjacentEdgeCW();
                from = from.getAdjacentEdgeCW();
            }
        }
        return sides;
    }


    public static int getInset(Insets insets, Edge edge)
    {
        return getInset(insets, edge.getOrientation(), edge.isOrigin());
    }

    // todo - test insets reveal

    public static Point scale(Point pt, double scale)
    {
        return scale(pt, scale, pt);
    }

    private static Point scale(Point src, double scale, Point target)
    {
        target.x = round(src.x*scale);
        target.y = round(src.y*scale);
        return target;
    }

    private static int round(double v)
    {
        return (int)v;
    }
}
